home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / forward.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-31  |  46.7 KB  |  1,690 lines

  1. /* Some of the code in this file was originally based on the following file:
  2.  * gateway.c : Paul Healy, EI9GL, 900818
  3.  *
  4.  * Rewrote forwarding mechanism to use "X-Forwarded-To" paradigm instead of
  5.  * "X-BBS-To", added timer support, etc.  Anders Klemets, SM0RGV, 901009.
  6.  */
  7.  /* Mods by G1EMM and WG7J */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include <time.h>
  12. #include "global.h"
  13. #include "config.h"
  14. #include "bm.h"
  15. #include "mailbox.h"
  16. #include "smtp.h"
  17. #include "cmdparse.h"
  18. #include "proc.h"
  19. #include "socket.h"
  20. #include "timer.h"
  21. #include "usock.h"
  22. #include "netuser.h"
  23. #include "ax25.h"
  24. #include "netrom.h"
  25. #include "nr4.h"
  26. #include "files.h"
  27. #include "mailfor.h"
  28.  
  29. #ifdef MBFWD
  30.  
  31. #define NOSUBCHANNEL (NUMMBX + 10)
  32. extern int MbForwarded;
  33. extern char MboxId[], MboxIdFwd[];
  34. extern int BBSdump;
  35. extern int MbBID, MbMID;
  36. #define ISPROMPT(s) (strlen(s) > 1 && s[strlen(s)-2] == '>')
  37. static struct timer fwdtimer;
  38. unsigned subchannels[NUMMBX];
  39. int subchannelusage[NUMMBX];
  40. int lastSessionSkipped;
  41. int FWDmode = 1, FWDpersonal = 1, FWDbulletins = 1, FWDreverse = 1;
  42. #ifdef LZW
  43. int FWDlzw = 1;
  44. #else
  45. int FWDlzw = 0;
  46. #endif
  47.  
  48. static char *findident __ARGS((char *str, int n, char *result));
  49. static void sendmsg __ARGS((struct mbx *m,int msgn,char *thebid));
  50. char *mbxtime __ARGS((char *line));
  51. static int fwdinit __ARGS((struct mbx *m));
  52. static char *fwdanybbs __ARGS((struct mbx *m,int *poll));
  53. static int timeok __ARGS((char *line));
  54. static void fwdtick __ARGS((void *v));
  55. static void fwdproc __ARGS((int, void *, void *));
  56. static int isconnbbs __ARGS((struct mbx *m));
  57. static void startfwd __ARGS((int a,void *v1,void *v2));
  58. static int openconn __ARGS((int argc,char *argv[],void *p));
  59. static int sendmsgtobbs __ARGS((struct mbx *m,int msgn,char *dest,int bulletin));
  60. static int makecl __ARGS((struct mbx *m,int msgn,char *dest,char *line,char *subj,char *bid,int *bul));
  61. static char *grabtext __ARGS((char *from,char *to,int marker));
  62. void forwardingSummary __ARGS((void));
  63. extern char *nntp_name_expansion __ARGS((char *name));
  64.  
  65.  
  66. #ifdef LZW
  67. static int
  68. dolzw(argc,argv,p)
  69. int argc;
  70. char *argv[];
  71. void *p;
  72. {
  73.     return setbool(&FWDlzw,"Forward using lzw",argc,argv);
  74. }
  75. #endif
  76.  
  77.  
  78. static int
  79. domode(argc,argv,p)
  80. int argc;
  81. char *argv[];
  82. void *p;
  83. {
  84.     return setbool(&FWDmode,"Forwarding enabled",argc,argv);
  85. }
  86.  
  87.  
  88. static int
  89. dopersonal(argc,argv,p)
  90. int argc;
  91. char *argv[];
  92. void *p;
  93. {
  94.     return setbool(&FWDpersonal,"Forwarding Personal Messages",argc,argv);
  95. }
  96.  
  97.  
  98. static int
  99. dobulletins(argc,argv,p)
  100. int argc;
  101. char *argv[];
  102. void *p;
  103. {
  104.     return setbool(&FWDbulletins,"Forwarding Bulletins",argc,argv);
  105. }
  106.  
  107.  
  108. static int
  109. doreverse(argc,argv,p)
  110. int argc;
  111. char *argv[];
  112. void *p;
  113. {
  114.     return setbool(&FWDreverse,"Reverse Forwarding Enabled",argc,argv);
  115. }
  116.  
  117. static int
  118. dosummary(argc,argv,p)
  119. int argc;
  120. char *argv[];
  121. void *p;
  122. {
  123.     forwardingSummary();
  124.     return 0;
  125. }
  126.  
  127. static int
  128. dostatus(argc,argv,p)
  129. int argc;
  130. char *argv[];
  131. void *p;
  132. {
  133. int i, first = 0;
  134.  
  135.     dobulletins (0, 0, 0);
  136. #ifdef LZW
  137.     dolzw (0, 0, 0);
  138. #endif
  139.     domode (0, 0, 0);
  140.     dopersonal (0, 0, 0);
  141.     doreverse (0, 0, 0);
  142.  
  143.     /* also give forwarding in progress report */
  144.     for(i = 0; i < NUMMBX; ++i)    {
  145.         if(Mbox[i] == NULLMBX)
  146.             continue;
  147.         if ((Mbox[i]->state == MBX_FORWARD) || (Mbox[i]->state == MBX_REVFWD))    {
  148.             if (!first)    {
  149.                 tprintf ("\nActive Forwarding Sessions:\n");
  150.                 first = 1;
  151.             }
  152.             tprintf ("     %-9s - %sForwarding\n", Mbox[i]->name, (Mbox[i]->state == MBX_REVFWD) ? "Reverse " : "");
  153.         }
  154.     }
  155.     return (0);
  156. }
  157.  
  158.  
  159. static struct cmds DFAR FWDcmds[] = {
  160.     "bulletins",    dobulletins,    0,    0,    NULLCHAR,
  161. #ifdef    LZW
  162.     "lzw",        dolzw,        0,    0,    NULLCHAR,
  163. #endif
  164.     "mode",        domode,        0,    0,    NULLCHAR,
  165.     "personal",    dopersonal,    0,    0,    NULLCHAR,
  166.     "reverse",    doreverse,    0,    0,    NULLCHAR,
  167.     "status",    dostatus,    0,    0,    NULLCHAR,
  168.     "summary",    dosummary,    0,    0,    NULLCHAR,
  169.     NULLCHAR,
  170. };
  171.  
  172.  
  173. int
  174. doforward(argc,argv,p)
  175. int argc;
  176. char *argv[];
  177. void *p;
  178. {
  179.     return subcmd(FWDcmds,argc,argv,p);
  180. }
  181.  
  182.  
  183.  
  184. /***************************************************************************
  185.    findident copies the 'n'th alphanumeric sequence from 'str' to result.
  186.    It returns a ptr to result. It returns "\0" for missing identifier etc.
  187.    Uses isalnum macro to decide on alphanumeric/non-alnum status.
  188. */
  189. static char *
  190. findident(str, n, result)
  191. char *str, *result;
  192. int n;
  193. {
  194.    int count; /* current identifier */
  195.    count = 0;
  196.    *result = '\0';
  197.    while ( (count<n) && (*str!='\0') ) { /* Process alnum or non alnum seq */
  198.       while ( (*str!='\0') && (!isalnum(*str)) ) /* Get rid of ';:.@%"# etc */
  199.          str++;
  200.       if ( (*str!='\0') && isalnum(*str) ) { /* this is an alnum seq */
  201.          count++;
  202.          while ( (*str!='\0') && (isalnum(*str) || (*str=='_')) )
  203.             if (count==n)
  204.                *result++ = *str++;
  205.             else str++;
  206.          if (count==n)
  207.             *result = '\0';
  208.          }
  209.       }
  210.    return result;
  211. }
  212.  
  213. extern char *Mbhaddress;
  214. extern char *Mbfwdinfo;
  215. extern char *Mbqth;
  216. extern int MbRSTYLE;
  217. extern char *Mbzip;
  218. extern int Mbsmtptoo;
  219. extern int Mbfullsvc;
  220. extern int UtcOffset;
  221. extern char shortversion[];
  222.  
  223.  
  224. static int
  225. checkone (line,str,sub)
  226. char *line, *str, *sub;
  227. {
  228. char *cp;
  229.  
  230.     if (!strnicmp (line, str, strlen(str)) && (cp = strstr (line, Hostname)) != NULLCHAR)    {
  231.         strcpy (cp, sub);
  232.         return 1;
  233.     }
  234.     return 0;
  235. }
  236.  
  237.  
  238. int
  239. adaptaddress (line)
  240. char *line;
  241. {
  242. char buf[60], *cp;
  243. int retval = 0;
  244.  
  245.     pax25(buf,Mycall);
  246.     if((cp = strchr(buf,'-')) != NULLCHAR)
  247.         *cp = '\0'; /* remove SSID */
  248.     strcat (buf, (Mbhaddress != NULLCHAR) ? Mbhaddress : "");
  249.     strcat (buf, "\n");
  250.     if (checkone (line, Hdrs[XMAILGROUP], buf))
  251.         return 1;
  252.     if (checkone (line, Hdrs[ERRORSTO], buf))
  253.         return 1;
  254.     return (checkone (line, Hdrs[REPLYTO], buf));
  255. }
  256.  
  257.  
  258. /**************************************************************************/
  259. /* sendmsg() modified to send the R: line always.
  260.  * also added some additional strings like qth and zipcode etc. to R: line.
  261.  * Original SMTP headers get forwarded optionally.
  262.  * 920114 - WG7J
  263.  */
  264.  
  265. static void
  266. sendmsg(m,msgn,thebid)
  267. struct mbx *m;
  268. int msgn;
  269. char *thebid;
  270. {
  271. char buf[LINELEN], tb[LINELEN], *cp;
  272. int len,rec = 0; /* rec is line-counter */
  273. long cnt;
  274. unsigned int msgid=0; /* message id number - WG7J */
  275. int col, ccnt;
  276. char c;
  277.  
  278.     /*point to start of this message in file*/
  279.     fseek(m->mfile,m->mbox[msgn].start,0);
  280.     /*get message size*/
  281.     cnt = m->mbox[msgn].size;
  282.  
  283.     /* If the data part of the message starts with "R:" the RFC-822
  284.      * headers will not be forwarded. Instead we will add an R:
  285.      * line of our own.
  286.      */
  287.     /* ALWAYS forward with "R:" line */
  288.     for(;;) {
  289.         /*read a line*/
  290.         if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  291.             break;
  292.         pwait (NULL);
  293.         /*adjust message character count*/
  294.         cnt -= strlen(buf);
  295.         if(rec == 1) {
  296.             /* look at the line following Received:
  297.              * This has the ID followed by ' ; date&time in arpa-format'
  298.              */
  299.             /*get the message number from the ID line - WG7J*/
  300.             if((cp=strstr(buf,"AA"))!= NULLCHAR)
  301.                 /*what follows is the message-number*/
  302.                 msgid = atoi(cp+2);
  303.             /*get the ARPA format date/time string*/
  304.             if((cp = strchr(buf,';')) != NULLCHAR){
  305.                 strcpy(tb,cp+1); /* point to the date of receipt */
  306.             }
  307.             /*ALWAYS send the R: line */
  308.             pax25(buf,Mycall);
  309.             if((cp = strchr(buf,'-')) != NULLCHAR)
  310.                 *cp = '\0'; /* remove SSID */
  311.             /*If mbox header is off, don't send the R: line*/
  312.         if (Mbfullsvc)    {
  313.                 if(!MbRSTYLE)    {
  314.                     usprintf(m->user,"R:%s @:%s%s%s ", mbxtime(tb), buf,
  315.                 (Mbhaddress != NULLCHAR) ? "." : "",
  316.                 (Mbhaddress != NULLCHAR) ? Mbhaddress : "");
  317.                 if (Mbfwdinfo)
  318.                 usprintf(m->user, "[%s] ", Mbfwdinfo);
  319.                     if (Mbqth)
  320.                 usprintf(m->user,"%s ", Mbqth);
  321.                 if (MbMID)
  322.                 usprintf(m->user,"#:%u ", msgid);
  323.                 if (Mbzip)
  324.                 usprintf(m->user,"Z:%s ", Mbzip);
  325.                     if (MbBID && (thebid[0] == '$'))
  326.                         usprintf(m->user, "$:%s", &thebid[1]);
  327.                     usprintf(m->user, "\n");
  328.             } else
  329.                 usprintf(m->user, "R:%s %d@%s%s%s\n", mbxtime(tb), msgid, buf, (Mbhaddress) ? "." : "",
  330.                 (Mbhaddress) ? Mbhaddress : "");
  331.         }
  332.             break;
  333.         }
  334.         /* The first Received: line is the one that we have added */
  335.         if(!rec && htype(buf) == RECEIVED)
  336.              ++rec;
  337.     }
  338.     /*Go past the SMTP headers to the data of the message.
  339.      *Check if we need to forward the SMTP headers!
  340.      *920114 - WG7J
  341.      */
  342.     for(;;) {
  343.         if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  344.             break;
  345.         pwait (NULL);
  346.         cnt -= strlen(buf);
  347.         if(*buf == '\n')    /* last header line */
  348.             break;
  349.         if (adaptaddress (buf))
  350.                    usputs(m->user,buf);
  351.         else if(Mbsmtptoo) { /*YES, forward SMTP headers TOO !*/
  352.             switch(htype(buf)) {
  353.                 case XFORWARD: /* Do not forward the "X-Forwarded-To:" lines */
  354.                 case STATUS:   /* Don't forward the "Status:" line either */
  355.                 case BBSTYPE:
  356.                 case SUBJECT:
  357.                 case TO:
  358.                 case DATE:
  359.                     break;
  360.                 case FROM:
  361.                     /* Don't forward the "From: " line either.
  362.                      * make it ">From: "
  363.                      */
  364.                     cp = strdup(buf);
  365.                     strcpy(buf,">");
  366.                     strcat(buf,cp);
  367.                     free(cp);        /*note fall-through*/
  368.                 default:
  369.                     usputs(m->user,buf);
  370.             }
  371.         }
  372.     }
  373.     /* If this is a message that originated locally,
  374.      * there are NO other R: headers
  375.      * in that case send a '\n',
  376.      * to separate the text from our R:-header - WG7J
  377.      */
  378.     if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  379.         return; /* NO text ??? */
  380.     cnt -= strlen(buf);
  381.     if(strncmp(buf,"R:",2)) /* NO R: found! */
  382.         /*Now a blank line, separating our headers and body*/
  383.         usputs(m->user,"\n");
  384.     if (!strncmp (Hdrs[RRECEIPT], buf, strlen(Hdrs[RRECEIPT])))    {  /* return receipt line */
  385.     if (!isarea (m->area))        /* only send if not a bulletin */
  386.         usputs(m->user,buf);
  387.     else
  388.         fgets(buf,sizeof(buf),m->mfile);  /* eat the blank line following */
  389.         cnt -= strlen(buf);
  390.     }
  391.     else
  392.         usputs(m->user,buf);
  393.  
  394.     /* the rest of the message is treated below */
  395. #ifdef nope
  396.     do {
  397.         len = min(cnt,sizeof(buf)-1);
  398.         if(fread(buf,1,len,m->mfile) != len)
  399.             break;
  400.         pwait (NULL);
  401.         cnt -= len;
  402.         buf[len] = '\0';
  403.         usputs(m->user,buf);
  404.     } while(cnt);
  405. #else
  406.         col = 0;
  407.         while (!feof(m->mfile) && cnt > 0) {
  408.             for (col = 0;  col < MAXBUF;) {
  409.                 c = getc(m->mfile);
  410.                 cnt--;
  411.                 if (feof(m->mfile) || cnt == 0) /* end this line */
  412.                     break;
  413.                 if (c == '\t') {
  414.                     ccnt = col + 8 - (col & 7);
  415.                     if (ccnt >= MAXBUF) /* end this line */
  416.                         break;
  417.                     while (col < ccnt)
  418.                         buf[col++] = ' ';
  419.                 } else {
  420.                     if (c == '\n')
  421.                         break;
  422.                     buf[col++] = c;
  423.                 }
  424.             }
  425.             if(col < MAXBUF)
  426.                 buf[col++] = '\n';
  427.             buf[col] = '\0';
  428.             usputs(m->user,buf);
  429.             pwait (NULL);
  430.         }
  431. #endif
  432. }
  433.  
  434. /* Parse a line for date and time in Arpanet format
  435.  * (Day, day Month year hh:mm:ss Zone) and return it in mailbox format
  436.  * (yymmdd/hhmmz)
  437.  */
  438. char *
  439. mbxtime(line)
  440. char *line;
  441. {
  442.     extern char *Months[];
  443.     static char buf[13];
  444.     char *cp;
  445.     int year,month,day,hour,minute,maxdays;
  446.  
  447.     cp = line;
  448.     while(isspace(*cp))    /* skip initial blanks */
  449.         ++cp;
  450.     if(*cp == '\0')
  451.         return NULLCHAR;
  452.     if(strlen(cp) < 22)
  453.         return NULLCHAR;
  454.     cp += 5;
  455.     day = atoi(cp);
  456.     if(*(++cp) != ' ')
  457.         ++cp;
  458.     ++cp;
  459.     for(month=0; month < 12; ++month)
  460.         if(strnicmp(Months[month],cp,3) == 0)
  461.             break;
  462.     if(month == 12)
  463.         return NULLCHAR;
  464.  
  465.     /* Get things, and adjust for GMT/UTC time - WG7J */
  466.     month++;
  467.     year = atoi(cp+4);
  468.     hour = atoi(cp + 7);
  469.     minute = atoi(cp + 10);
  470.  
  471.     if(UtcOffset != 0) {
  472.         hour -= UtcOffset;
  473.         /* See if we went past midnight */
  474.         if(hour > 23) {
  475.             hour -= 24;
  476.             ++day;
  477.             /*Check for next month*/
  478.             if(month == 2) { /*February, check leap-year*/
  479.                 if((year%4) == 0)
  480.                     maxdays = 29;
  481.                 else
  482.                     maxdays = 28;
  483.             } else {
  484.                 if((month%2) == 0)
  485.                     maxdays = 30;
  486.                 else
  487.                     maxdays = 31;
  488.             }
  489.             if(day > maxdays) { /*adjust month*/
  490.                 day = 1;
  491.                 if(++month == 13) { /*next year*/
  492.                     month = 1;
  493.                     year++;
  494.                 }
  495.             }
  496.         } else
  497.             if(hour < 0) { /*previous day !*/
  498.                 hour += 24;
  499.                 if(--day == 0) { /*previous month*/
  500.                     if(--month == 0) { /*previous year*/
  501.                         year--;
  502.                         month = 12;
  503.                     }
  504.                     if(month == 2) { /* February, check leap year */
  505.                         if((year%4) == 0)
  506.                             day = 29;
  507.                         else
  508.                             day = 28;
  509.                     } else {
  510.                         if((month%2) == 0)
  511.                             day = 30;
  512.                         else
  513.                             day = 31;
  514.                     }
  515.                 }
  516.             }
  517.     }
  518.  
  519.     sprintf(buf,"%02d%02d%02d/%02d%02dz",year,month,day,hour,minute);
  520.     return buf;
  521. }
  522.      
  523. static char *
  524. grabtext(from, to, marker)
  525. char *from, *to;
  526. int marker;
  527. {
  528.    while (*from!=marker)
  529.       *to++ = *from++;
  530.    *to = '\0';
  531.    return from+1;
  532. }
  533.  
  534. /* Makes a command line and returns -1 if the message cannot be sent. */
  535. static int
  536. makecl(m, msgn, dest, line, subj, bid, bul)
  537. struct mbx *m;
  538. int msgn;        /* Message number */
  539. char *dest;        /* Destination address to use instead of To: line */
  540. char *line, *subj;    /* Buffers to keep command line and subject */
  541. char *bid;    /* Buffer to keep bid */
  542. int *bul;       /* True if message is in public message area */
  543. {
  544.    int bulletin = *bul;
  545.    int foundbid = 0;
  546.    char to[LINELEN], atbbs[LINELEN], from[LINELEN], buf[LINELEN], *cp;
  547.  
  548.    if(m->mfile == NULLFILE)
  549.     return -1;
  550.  
  551.    if(!bulletin && (m->mbox[msgn].status & BM_READ))
  552.     return -1;    /* the message was already read */
  553.    fseek(m->mfile,m->mbox[msgn].start,0);
  554.    *bid = *to = *atbbs = *from = '\0';
  555.    if(subj != NULLCHAR)
  556.     *subj = '\0';
  557.    m->stype = bulletin ? 'B' : 'P';    /* default to SB or SP */
  558.    while (fgets(buf,sizeof(buf),m->mfile)) {
  559.       if (buf[0] == '\n')
  560.          break; /* envelope finished */
  561.       switch (htype(buf)) {
  562.       case TO:
  563.         /* The following code tries to parse "To: " lines where the
  564.          * address looks like any of the following: "to@atbbs",
  565.          * "<to@atbbs>", "<to%atbbs@host>" and with possible spaces
  566.          * surrounding the '<>' characters.
  567.          */
  568.         if((cp = getaddress(buf,0)) == NULLCHAR)
  569.             break;
  570.         strcpy(to,cp);
  571.         if((cp = strchr(to,'%')) != NULLCHAR) { /* look for a '%' */
  572.             strcpy(atbbs,cp + 1);
  573.             *cp = '\0';    /* "to" ends at the '%' character */
  574.         }
  575.         else {    /* no '%' but maybe a '@'? */
  576.             if((cp = strchr(to,'@')) != NULLCHAR) {
  577.                 strcpy(atbbs,cp + 1);
  578.                 *cp = '\0';   /* "to" ends at the '@' character */
  579.             }
  580.         }
  581.         if(*atbbs != '\0')        /* either '%' or '@' found */
  582.          /* cut "atbbs" at the first '@' character */
  583.          for(cp = atbbs; *cp != '\0'; ++cp)
  584.               if(*cp == '@') {
  585.                *cp = '\0';
  586.                break;
  587.               }
  588.         /* "to" or "atbbs" should not be more than 6 characters (ALEN).
  589.          * If "to" is too long, it might simply be because the area name
  590.          * is longer than 6 characters, but it might also be because
  591.          * the address on the To: line is in an obscure format that we
  592.          * failed to parse (eg '!' character notation.)
  593.          */
  594.         if(strlen(to) > ALEN) {
  595.         /* Play safe and set "to" and "atbbs" to the area name */
  596.         strcpy(to,m->area);
  597.         strcpy(atbbs,m->area);
  598.               }
  599.  
  600. /* why would we want to add an atbbs if the message doesn't have one originally ?!?! */
  601. #if 0
  602.         if(*atbbs == '\0')
  603.         strcpy(atbbs,to);
  604. #endif
  605.  
  606.               to[ALEN] = '\0';
  607.         /* Only if the BBS supports "hierarchical routing designators"
  608.          * is the atbbs field allowd to be longer than 6 characters and
  609.          * have dots in it.
  610.          */
  611.         if((m->sid & MBX_HIER_SID) == 0) {
  612.          atbbs[ALEN] = '\0';    /* 6 character limit */
  613.          if((cp = strchr(atbbs,'.')) != NULLCHAR)
  614.               *cp = '\0';    /* cut "atbbs" at first dot */
  615.         }
  616.             break;
  617.       case MSGID:
  618.         /* The following code distinguishes between two different types
  619.          * of Message-IDs: <abcde@callsign.bbs> and <abcde@host.domain>.
  620.          * The first type is converted to $abcde and the second to
  621.          * $abcde_host.domain. This preserves compability with BBSes.
  622.          */
  623.         if((cp = getname(buf)) == NULLCHAR)
  624.             break;
  625.         bid[0] = '$';
  626.         strcpy(&bid[1],cp);
  627.         cp = strchr(bid,'@');
  628.         /* A trailing ".bbs" indicates that the Message-ID was generated
  629.          * from a BBS style message, and not a RFC-822 message.
  630.          */
  631.         if(cp != NULLCHAR && stricmp(&bid[strlen(bid) - 4], ".bbs") == 0) {
  632.             *cp = '\0'; /*retain the bid given by user*/
  633.             foundbid = 1; /* Indicate we found a 'real' bid - WG7J */
  634.         } else {
  635.             /*This is a message with no bid, MSGID is <msg#@hostname>
  636.              *make this BID style '$msg#_host'
  637.              *ie. replace @ with _ and
  638.              *cut off after first part of hostname    - WG7J
  639.              */
  640.             *cp = '_';
  641.             if((cp = strchr(cp,'.')) != NULLCHAR)
  642.                 *cp = '\0';
  643.         }
  644.         bid[13] = '\0';    /* BIDs should be no longer than 13 bytes */
  645.               break;
  646.       case SUBJECT:
  647.         if(subj != NULLCHAR) {
  648.               (void) grabtext(buf+9, subj, '\n');
  649.             /* Make sure subject isn't empty - WG7J */
  650.             cp = subj;
  651.             while(*cp == ' ' || *cp == '\t')
  652.                 cp++;
  653.             if(*cp == '\0')
  654.                 strcpy(subj,"None");
  655.         }
  656.             break;
  657.       case FROM:
  658.         if((cp = getaddress(buf,0)) != NULLCHAR) {
  659.             if (!strnicmp (cp,"REQSVR",6) || !strnicmp (cp, "MAILER-DAEMON", 13))    {    /* MAILER-DAEMON going out->call sign */
  660.                 pax25(buf,Mycall);
  661.                 cp = strchr (buf, '-');
  662.                 if (cp)
  663.                     *cp = 0;
  664.                 strcpy (from, buf);
  665.             } else
  666.             findident(cp, 1, from);        /* cp points to from@domain */
  667.         from[ALEN] = '\0';    /* 6 character limit */
  668.         }
  669.             break;
  670.       case XFORWARD:
  671.         if((cp = getaddress(buf,0)) == NULLCHAR)
  672.          break;
  673.         if(stricmp(m->name,cp) == 0)    {
  674.             
  675.         /* This message has already been forwarded, abort */
  676.         return -1;
  677.         }
  678.         break;
  679.       case BBSTYPE:
  680.         m->stype = buf[16];
  681.             /* if it comes from a NTS area,
  682.              * always send as traffic, ie 'ST' - WG7J
  683.              */
  684.             if(!strnicmp(m->area,"nts",3))
  685.                 m->stype = 'T';
  686.             if(m->stype == 'B') {
  687.                 bulletin = 1;
  688.                 *bul = 1;
  689.             }
  690.         break;
  691.       default:
  692.         break;
  693.       }
  694.    }
  695.    /* Check for an invalid RFC-822 header */
  696.    if((to[0] == '\0' && ((dest != NULLCHAR && *dest == '\0') ||
  697.       dest == NULLCHAR)) || from[0] == '\0')
  698.     return -1;
  699.  
  700.    if(line != NULLCHAR) {
  701.     if(dest != NULLCHAR && *dest != '\0'){
  702.          /* strip off hierarchical routing designators from the predefined
  703.           * destination address if they are not supported
  704.           */
  705.          if((m->sid & MBX_HIER_SID) == 0 && (cp = strchr(dest,'.')) !=
  706.            NULLCHAR)
  707.         *cp = '\0';
  708.          sprintf(line, "S%c %s < %s ", m->stype, dest, from);
  709.     }
  710.     else
  711.          sprintf(line, "S%c %s%s%s < %s ", m->stype, to, (*atbbs) ? " @ " : "", atbbs, from);
  712. #ifdef nope
  713.     /* This fixes the problem with personal MIDs being the same with
  714.      * messages generated from aliases, RMAIL, or mail-groups. Changes
  715.      * the bid from $abcde_host.domain to $abcde_destinationuser. - KO4KS
  716.      */
  717.     if (!bulletin && (m->sid & MBX_MID))    {
  718.         if ((cp = strrchr (bid, '_')) != NULLCHAR)    {
  719.             *cp++;
  720.             if (!strnicmp (Hostname, cp, strlen(cp)))    {
  721.                 *(cp-1) = '%';
  722.             if(dest != NULLCHAR && *dest != '\0')
  723.                 strcpy (cp, dest);
  724.             else
  725.                 strcpy (cp, to);
  726.             bid[13] = '\0';
  727.             if ((cp = strchr (bid, '.')) != NULLCHAR)
  728.                 *cp = '\0';
  729.         }
  730.     }
  731.     }
  732. #endif
  733.  
  734.     /* This keeps us from adding a MID to someone else's message */
  735.     if (!foundbid)    {    /* if one wasn't found, but GENERATED */
  736.     fgets(buf,sizeof(buf),m->mfile);    /* get first data line */
  737.     if (!strnicmp (buf, "R:", 2))    /* if it has at least one "R:" line */
  738.         bid[0] = '\0';        /* blank out the MID */
  739.     }
  740.  
  741.     /* convert the bid to upper case for compatability with BBSs */
  742.     strupr (bid);
  743.  
  744.     /* Add the bid to bulletins,
  745.      * AND ALSO to anything that came in with a bid !
  746.      * Takes care off duplicate 'SP SYSOP@xxx $BID' problems - WG7J
  747.      * ALSO add it to ALL messages if the remote system supports MID's - WG7J
  748.      */
  749. /*    if((m->sid & MBX_MID) || ((bulletin || foundbid) & (m->sid & MBX_SID))) */
  750.       if((m->sid & MBX_MID) || (bulletin && (m->sid & MBX_SID)))
  751.          strcat(line,bid);
  752.     strcat(line,"\n");
  753.    }
  754.    return 0;
  755. }
  756.  
  757. static int /* 0 = ok, -1 = problem so disc */
  758. sendmsgtobbs(m, msgn, dest, bulletin)
  759. struct mbx *m;
  760. int msgn;
  761. char *dest;        /* Optional destination address to override To: line */
  762. int bulletin;
  763. {
  764. int result = -1;
  765. char line[64], subj[256], thebid[LINELEN];
  766.  
  767.     if(makecl(m, msgn, dest, line, subj, thebid, &bulletin) == -1)
  768.         return 0;    /* do not forward this particular message */
  769.     tputs(line);         /* Send mail offer to bbs */
  770.     rip(line);
  771.     usflush(m->user);
  772.     if (recvline (m->user, m->line, MBXLINE) != -1 )     {
  773.         if (m->line[0] == 'O' || m->line[0] == 'o' || (m->sid & MBX_SID) == 0)     {
  774.             /* Got 'OK' or any line if the bbs is unsofisticated */
  775.             tprintf("%s\n", subj);
  776.             sendmsg(m,msgn,thebid);   /* send the message */
  777.             tputs("/EX\n"); /* was 0x1a */
  778.             usflush(m->user);
  779.             /* get F> for a good deliver */
  780.             while (recvline (m->user, m->line, MBXLINE) != -1 )
  781.                 if (ISPROMPT(m->line))     {
  782.                     log(m->user,"MBOX bbs mail sent: %s ", line);
  783. #ifdef notagain
  784.                     if(bulletin)
  785.                         m->mbox[msgn].status |= BM_FORWARDED;
  786.                     else    {
  787. #endif
  788.                     if(!bulletin)    {
  789.                         m->mbox[msgn].status |= BM_DELETE;
  790.                         statusCtl (m->area, "ctl", &m->mbox[msgn], msgn, 0);
  791.                         m->change |= CHG_DELETE;
  792.                     }
  793.                     result = 0;
  794.                     MbForwarded++;
  795.                     break;
  796.                 }
  797.         } else { /* OK response not received from bbs */
  798.             if (m->line[0] == 'N' || m->line[0] == 'n') { /* 'NO' respone */
  799.                       log(m->user,"MBOX bbs mail refused: %s\n     %s",line,m->line);
  800. #ifdef notagain
  801.                 /* Mark refused message as forwarded if it is a bulletin.
  802.                  * The message was probably a duplicate. Non-bulletin
  803.                  * messages are sent without BID, so they cannot be dected
  804.                  * as duplicates. The reason why it was refused is probably
  805.                  * because the address was invalid. Retry later.
  806.                  */
  807.                 if(bulletin)    {
  808.                             m->mbox[msgn].status |= BM_FORWARDED;
  809.                     statusCtl (m->area, "ctl", &m->mbox[msgn], msgn, 0);
  810. /*                            m->change = 1;    */
  811.                         }
  812. #endif
  813.                 result = 0;    /* don't want it, so skip it! */
  814.             }
  815.             /* should get a F> here */
  816.             while (recvline (m->user, m->line, MBXLINE) != -1 )
  817.                 if (ISPROMPT(m->line))         {
  818.                           result = 0;
  819.                     break;
  820.                       }
  821.         }
  822.     } /* OK or NO here */
  823.     if (m->stype != 'B')
  824.         msgiddelete (&thebid[1]);
  825.     return result;
  826. }
  827.  
  828.  
  829. /* Forward messages from one message area.  */
  830. static int
  831. fwdthisarea (m, fwd, area, newto)
  832. struct mbx *m;
  833. FILE *fwd;
  834. char *area, *newto;
  835. {
  836. int  bulletin;
  837. long bid, pos = 0, save;
  838. int index, changed = 0, i;
  839. int err = 0;
  840. char *cp;
  841. struct    let *cmsg;
  842. char line[80];
  843.  
  844.     pwait (NULL);
  845.     bulletin = isarea(area);    /* public area */
  846.     if (bulletin && !FWDbulletins)
  847.         return err;
  848.     if (!bulletin && !FWDpersonal)
  849.         return err;
  850.     rewind (fwd);
  851.     while(!err && fgets(line,MBXLINE,fwd) != NULLCHAR) {
  852.         fflush (fwd);
  853.         pwait (NULL);
  854.         if (*line != '*')    {    /* if not already done */
  855.             if ((cp = strpbrk(&line[1]," \t")) != NULLCHAR)
  856.                 *cp++ = '\0';
  857.             if (!stricmp (area, &line[1]))    { /* only if for us */
  858.                 bid = atol (cp);
  859.                 if (!changed)    {    /* if not already changed */
  860.                     changearea(m,area, (int) 1);
  861.                     changed = 1;
  862.                 }
  863.                 index = 0;
  864.                 for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)
  865.                     if (bid == cmsg->bid)    {
  866.                         index = i;
  867.                         break;
  868.                     }
  869.                 if (index && !(cmsg->status & (BM_ONHOLD | BM_DELETE)))    {
  870.                     if(sendmsgtobbs(m, index, newto, bulletin) == -1)
  871.                         err = 1;    /* abort */
  872.                 }
  873.                 if (!index || (!err && !(cmsg->status & BM_ONHOLD)))    {
  874.                     clearerr(fwd);
  875.                     save = ftell (fwd);
  876.                     fseek (fwd, pos, SEEK_SET);
  877.                     fputc ('*', fwd);    /* mark as done! */
  878.                     fflush (fwd);
  879.                     fseek (fwd, save, SEEK_SET);
  880.                 }
  881.             }
  882.         }
  883.         pos = ftell (fwd);    /* get new backup position */
  884.     }
  885.     return err;
  886. }
  887.  
  888.  
  889. /* This is the main entry point for reverse forwarding. It is also used
  890.  * for normal, "forward", forwarding.
  891.  */
  892. int
  893. dorevfwd(argc,argv,p)
  894. int argc;
  895. char *argv[];
  896. void *p;
  897. {
  898. char oldarea[64], *area, *cp;
  899. struct mbx *m;
  900. int err = 0;
  901. unsigned i = NOSUBCHANNEL;
  902. FILE *fwd;
  903. long thesize, theend, thetop, newsize;
  904. char name[256];
  905.  
  906.     m = (struct mbx *)p;
  907.     /* indicate we are doing reverse forwarding, if we are not already
  908.      * doing normal forwarding.
  909.      */
  910.     if(m->state != MBX_FORWARD)    {
  911.         if (!FWDreverse)
  912.             goto notallowed;
  913.         m->state = MBX_REVFWD;
  914.         if ((m->sid & MBX_SID) && m->mysize)
  915.                 smtptick(NULL);        /* wake SMTP to send that mail */
  916.             m->mysize = 0;
  917.         }
  918.     if(fwdinit(m) != -1)     {
  919.         strcpy(oldarea,m->area);
  920.         sprintf (name, "%s/%s.fwd", Mailspool, m->name);
  921.         nntp_name_expansion (name);
  922.         strcat (name, ".fwd");
  923.         if((fwd = fopen(name,UPDATE_TEXT)) == NULLFILE)
  924.             return 0;    /* shouldn't happen except with reverse fwd */
  925.         log(m->user,"MBOX %sforwarding mail to: %s ", (m->state == MBX_REVFWD) ? "reverse " : "", m->name);
  926.         thesize = filelength(fileno(fwd));    /* so we know if any new */
  927.         thetop = ftell (m->tfile);
  928.         while(!err)    {
  929.             if (m->privs & EXCLUDED_CMD)
  930.                 break;
  931.             newsize = filelength(fileno(fwd));
  932.             if (thesize != newsize)    {
  933.                 /* if new mail came in to forward, start back
  934.                    up at the top of the areas to forward.
  935.                    This allows you to push personal traffic
  936.                    at highest priority */
  937.                 thesize = newsize;
  938.                 fseek (m->tfile, thetop, 0);
  939.             }
  940.             if (fgets(m->line,MBXLINE,m->tfile) == NULLCHAR)
  941.                 break;
  942.             if(*m->line == '-')    /* end of record reached */
  943.                 break;
  944.             if(*m->line == '#')    /* skip comments */
  945.                 continue;
  946.             if (*m->line == '=')    {    /* subchannel number */
  947.                 i = atoi (&m->line[1]);
  948.                 if (i > NUMMBX || subchannelusage[i] == subchannels[i])    {    /* maxed out */
  949.                     err = 1;
  950.                     i = NOSUBCHANNEL;
  951.                     continue;
  952.                 } else
  953.                     subchannelusage[i]++;
  954.             }
  955.             rip(m->line);        /* adds extra null at end */
  956.             if ((cp = strpbrk(m->line," \t")) != NULLCHAR)
  957.                 *cp = '\0';
  958.             if(*m->line == '\0' || *m->line == '.' || *m->line == '+' || *m->line == '@')
  959.                 continue;
  960.             /* get the optional destination field, cp will point
  961.              * at null byte if it is missing.
  962.              */
  963.             cp = &m->line[strlen(m->line)] + 1;
  964.             while(*cp != '\0' && isspace(*cp)) /* strip blanks */
  965.                  ++cp;
  966.             cp = strdup(cp);
  967.             area = strdup(m->line);
  968.             err = fwdthisarea (m, fwd, area, cp);
  969.             free(cp);
  970.             free(area);
  971.         }
  972.         fclose(m->tfile);
  973.         m->tfile = NULLFILE;
  974.         if(*oldarea != '\0')
  975.             changearea(m,oldarea, (int) 1);
  976.         theend = filelength(fileno (fwd));
  977.         if (!err && thesize == theend)        {
  978.             rewind (fwd);
  979.             while(fgets(m->line,MBXLINE,fwd) != NULLCHAR) {
  980.                 pwait (NULL);
  981.                 if (*m->line != '*')    {    /* if not already done */
  982.                     err = 1;
  983.                     break;
  984.                 }
  985.             }
  986.             fclose (fwd);
  987.             if (!err)
  988.                 remove (name);
  989.         } else
  990.             fclose (fwd);
  991.     }
  992.     if (i != NOSUBCHANNEL)
  993.         subchannelusage[i]--;
  994.     if(m->state == MBX_FORWARD)
  995.         return 0;
  996. notallowed:
  997.     tprintf("*** Done\n");
  998. /*    if((m->sid & MBX_RLI_SID) || (m->sid & MBX_FBB))    */    /* disconnect if it is a W0RLI or FBB bbs */
  999.     if(m->sid & MBX_RLI_SID)    /* disconnect if it is a W0RLI bbs */
  1000.         return domboxbye(0,NULL,m);
  1001.     return 0;
  1002. }
  1003.  
  1004. /* Read the forward file for a record for the connected BBS. If found,
  1005.  * return 0 if this is the right time to forward, m->tfile is left pointing
  1006.  * at the first message area to be forwarded.
  1007.  * returns -1, also, if nothing queued for forwarding.
  1008.  */
  1009. static int
  1010. fwdinit(m)
  1011. struct mbx *m;
  1012. {
  1013. char host[80];
  1014. char name[256];
  1015. int start = 1;
  1016.  
  1017.     if((m->tfile = fopen(Forwardfile,READ_TEXT)) == NULLFILE)
  1018.         return -1;
  1019.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  1020.         if(*m->line == '\n')
  1021.             continue;
  1022.         if(*m->line == '#')
  1023.             continue;
  1024.         /* lines starting with '-' separate the forwarding records */
  1025.         if(*m->line == '-') {
  1026.             start = 1;
  1027.             continue;
  1028.         }
  1029.         if(start) {
  1030.             start = 0;
  1031.             /* get the name of this forwarding record */
  1032.             findident(m->line,1,host);
  1033.             if(stricmp(m->name,host) == 0) {
  1034.                 if(!timeok(m->line))
  1035.                     break;
  1036.                 sprintf (name, "%s/%s.fwd", Mailspool, host);
  1037.                 if (access (name, 0))    /* nothing in this area! */
  1038.                     break;
  1039.                 /* eat the connect command line */
  1040.                 do    {
  1041.                     fgets(m->line,MBXLINE,m->tfile);
  1042.                 } while (*m->line == '#' || *m->line == '\n');
  1043.                 return 0;
  1044.             }
  1045.         }
  1046.     }
  1047.     fclose(m->tfile);
  1048.     m->tfile = NULLFILE;
  1049.     return -1;
  1050. }
  1051. /* Read the forward file for a record for the connected BBS. If found,
  1052.  * determine if this is the right time to forward, and return the command
  1053.  * line to establish a forwarding connection. m->tfile is left pointing
  1054.  * at the first message area to be forwarded.
  1055.  */
  1056. static char *
  1057. fwdanybbs(m, poll)
  1058. struct mbx *m;
  1059. int *poll;
  1060. {
  1061.     char host[80];
  1062.     int start = 1, i;
  1063.     if(m->tfile == NULLFILE && (m->tfile = fopen(Forwardfile,READ_TEXT))
  1064.                     == NULLFILE)
  1065.         return NULLCHAR;
  1066.     *poll = 0;  /* Default to no polling */
  1067.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  1068.         if(*m->line == '\n')
  1069.             continue;
  1070.         if(*m->line == '#')
  1071.             continue;
  1072.         /* lines starting with '-' separate the forwarding records */
  1073.         if(*m->line == '-') {
  1074.             start = 1;
  1075.             continue;
  1076.         }
  1077.         if(start) {
  1078.             start = 0;
  1079.             /* get the name of this forwarding record */
  1080.             findident(m->line,1,host);
  1081.             strcpy(m->name,host);
  1082.             if(!timeok(m->line))
  1083.                 continue;    /* too late or too early */
  1084.             /* Check for polling - WG7J */
  1085.             i=2;
  1086.             findident(m->line,2,host);
  1087.             while(*host) {
  1088.                 if(*host == 'P' || *host == 'p') {
  1089.                     *poll = 1;
  1090.                     break;
  1091.                 }
  1092.                 i++;
  1093.                 findident(m->line,i,host);
  1094.             }
  1095.             /* get the connect command line */
  1096.             do    {
  1097.                 fgets(m->line,MBXLINE,m->tfile);
  1098.             } while (*m->line == '#' || *m->line == '\n');
  1099.             return strdup(m->line);
  1100.         }
  1101.     }
  1102.     fclose(m->tfile);
  1103.     m->tfile = NULLFILE;
  1104.     return NULLCHAR;
  1105. }
  1106.  
  1107. /* get any groups of four digits that specify the begin and ending hours of
  1108.  * forwarding. Returns 1 if forwarding may take place.
  1109.  */
  1110. static int
  1111. timeok(line)
  1112. char *line;
  1113. {
  1114.     char hours[80], *now;
  1115.     long t;
  1116.     int t1, t2, pos = 2;
  1117.     findident(line,pos++,hours);
  1118.     if(*hours == '\0')
  1119.         return 1;    /* no digits default to 0023, ie. anytime */
  1120.     time(&t);
  1121.     now = ctime(&t) + 11;
  1122.     *(now + 2) = '\0';
  1123.     while(*hours != '\0') {
  1124.         t1 = (*hours - '0') * 10 + (*(hours+1) - '0');
  1125.         t2 = (*(hours+2) - '0') * 10 + (*(hours+3) - '0');
  1126.         if(atoi(now) >= t1 && atoi(now) <= t2)
  1127.             return 1;        /* right in time */
  1128.         findident(line,pos++,hours);    /* get next group if any */
  1129.     }
  1130.     return 0;    /* too early or too late */
  1131. }
  1132.  
  1133. int
  1134. dombtimer(argc,argv,p)
  1135. int argc;
  1136. char *argv[];
  1137. void *p;
  1138. {
  1139.     if(argc < 2){
  1140.         tprintf("Forwarding timer: %lu/%lu\n",
  1141.             read_timer(&fwdtimer)/1000L,
  1142.             dur_timer(&fwdtimer)/1000L);
  1143.         return 0;
  1144.     }
  1145.     stop_timer (&fwdtimer);    /* just in case */
  1146.     fwdtimer.func = (void (*)())fwdtick;/* what to call on timeout */
  1147.     fwdtimer.arg = NULL;        /* dummy value */
  1148.     set_timer(&fwdtimer,atol(argv[1])*1000L); /* set timer duration */
  1149.     start_timer(&fwdtimer);     /* fire it up */
  1150.     return 0;
  1151. }
  1152.  
  1153. int
  1154. dombkick(argc,argv,p)
  1155. int argc;
  1156. char *argv[];
  1157. void *p;
  1158. {
  1159.     fwdtick (NULL);
  1160.     return 0;
  1161. }
  1162.  
  1163.  
  1164. /* MDMII: fwdproc is the old fwdtick.   But, since it can call mspause, which is
  1165.  * very very bad for timer functions :-( this has been converted to a server.
  1166.  */
  1167. static void
  1168. fwdtick(v)
  1169. void *v;
  1170. {
  1171.     start_timer(&fwdtimer);        /* and restart the timer */
  1172.     if (FWDmode)
  1173.         if (newproc ("forward daemon", 2048, fwdproc, 0, NULL, NULL, 0) == NULLPROC)
  1174.             log (-1, "Couldn't start Forwarding process");
  1175. }
  1176.  
  1177.  
  1178. /* called when the forward timer expires or explicitly by dombkick() */
  1179. static void
  1180. fwdproc(nerf,v1,v2)
  1181. int nerf;        /* unused */
  1182. void *v1, *v2;    /* unused */
  1183. {
  1184. char *cc, *cp;
  1185. struct mbx *m;
  1186. unsigned i;
  1187. int bulletin, poll, skip = 0;
  1188. char name[256];
  1189. time_t t;
  1190.  
  1191.     if(Mtrace)
  1192.             printf("mailbox: forward started\n");
  1193.     if((m = newmbx()) == NULLMBX){
  1194.         if(Mtrace)
  1195.             printf("forward: unable to start new maibox\n");
  1196.         return;
  1197.     }
  1198.     time(&t);
  1199.     m->logontime = (long) t;
  1200.     m->user = Curproc->output;
  1201.     m->name[0] = 0;
  1202.     m->state = MBX_TRYING;
  1203.     lastSessionSkipped = 0;
  1204.     while((cc = fwdanybbs(m,&poll)) != NULLCHAR) {
  1205.         i = NOSUBCHANNEL;
  1206.         if(Mtrace)
  1207.                 printf("mailbox: examining '%s'\n", m->name);
  1208.         pwait (NULL);
  1209.         if(isconnbbs(m))     {
  1210.             /* already connected to this BBS, skip it */
  1211.             skip = 1;
  1212.             if (Mtrace)
  1213.                 printf ("fwd: '%s' already connected\n", m->name);
  1214.         }
  1215.         while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  1216.             if(*m->line == '#')
  1217.                 continue;
  1218.             if(*m->line == '\n')
  1219.                 continue;
  1220.             
  1221.             if(*m->line == '-') {    /* end of record reached */
  1222.                 skip = 0;
  1223.                 break;
  1224.             }
  1225.             if (*m->line == '=')     /* sub-channel info */
  1226.                 i = atoi (&m->line[1]);
  1227.             if((cp = strpbrk(m->line," \t")) != NULLCHAR)
  1228.                 *cp = '\0';
  1229.             if(skip || *m->line == '\0' || *m->line == '.' || \
  1230.                 *m->line == '+' || *m->line == '@')
  1231.                 continue;
  1232.             pwait (NULL);
  1233.             /* If we poll, there is no need to check message area, since this
  1234.              * is also done later. It will speed things up here - WG7J
  1235.              */
  1236.             if (!poll)    {    /* don't need if polling */
  1237.                 sprintf (name, "%s/%s.fwd", Mailspool, m->name);
  1238.                 if(Mtrace)
  1239.                         printf("mailbox: checking for file '%s'\n", name);
  1240.             }
  1241.             skip = 1;
  1242.             if (poll || !access (name, 0))    {
  1243.                 if (i != NOSUBCHANNEL || subchannelusage[i] == subchannels[i])    {    /* maxed out */
  1244.                     lastSessionSkipped = 1;
  1245.                     continue;
  1246.                 }
  1247.                 if(Mtrace)
  1248.                     printf("forward: to %s\n",m->name);
  1249.                 if (i != NOSUBCHANNEL)
  1250.                     subchannelusage[i]++;
  1251.                 newproc("Mbox forwarding", 3072,startfwd, i, (void *)cc,(void *)strdup(m->name),0);
  1252.             } else
  1253.                 free (cc);
  1254.             cc = NULLCHAR;
  1255.         }
  1256.         free(cc);
  1257.     }
  1258.     exitbbs(m);
  1259. }
  1260.  
  1261. /* returns 1 if m->name matches the name of another connected mailbox. */
  1262. static int
  1263. isconnbbs(m)
  1264. struct mbx *m;
  1265. {
  1266.     int i;
  1267.     for(i = 0; i < NUMMBX; ++i)
  1268.         if(Mbox[i] != NULLMBX && Mbox[i] != m &&
  1269.             stricmp(m->name,Mbox[i]->name) == 0)
  1270.                 return 1;
  1271.     return 0;
  1272. }
  1273.  
  1274. /* possible commands on the command line in the forwarding file */
  1275. static struct cmds cfwdcmds[] = {
  1276.     "tcp",        openconn,    0, 0, NULLCHAR,
  1277.     "telnet",    openconn,    0, 0, NULLCHAR,
  1278. #ifdef AX25
  1279.     "ax25",        openconn,    0, 0, NULLCHAR,
  1280.     "connect",    openconn,    0, 0, NULLCHAR,
  1281. #endif
  1282. #ifdef NETROM 
  1283.     "netrom",    openconn,    0, 0, NULLCHAR,
  1284. #endif
  1285.     NULLCHAR
  1286. };
  1287.  
  1288. static void
  1289. fwdcleanup (index, m, string)
  1290. int index;
  1291. struct mbx *m;
  1292. char *string;
  1293. {
  1294.     exitbbs(m);
  1295.     if(Mtrace && string)
  1296.         printf(string, m->name);
  1297.     if (index != NOSUBCHANNEL)
  1298.         subchannelusage[index]--;
  1299.     if (lastSessionSkipped)
  1300.         fwdtick (NULL);
  1301. }
  1302.  
  1303.  
  1304. /* this function is called whenever the forwarding timer expires */
  1305. static void
  1306. startfwd(a,v1,v2)
  1307. int a;
  1308. void *v1, *v2;
  1309. {
  1310. struct mbx *m;
  1311. char *cc;
  1312. int32 timeout;
  1313. int rval;
  1314. char *cp;
  1315. char Continue[MBXLINE];
  1316. time_t t;
  1317.  
  1318.     cc = (char *) v1;
  1319.     if((m = newmbx()) == NULLMBX) {
  1320.         free(cc);
  1321.         free((char *)v2);
  1322.         if (a != NOSUBCHANNEL)
  1323.             subchannelusage[a]--;
  1324.         return;
  1325.     }
  1326.     time(&t);
  1327.     m->logontime = (long) t;
  1328.     strcpy(m->name,(char *)v2);
  1329.     free((char *)v2);
  1330.     m->state = MBX_TRYING;
  1331.     /* open the connection, m->user will be the new socket */
  1332.     if(cmdparse(cfwdcmds,cc,(void *)m) == -1) {
  1333.         free(cc);
  1334.         fwdcleanup (a, m, "forward: unknown protocol\n");
  1335.         return;
  1336.     }
  1337.     free(cc);
  1338.     m->state = MBX_FORWARD;
  1339.     sockowner(m->user,Curproc);
  1340.     close_s(Curproc->output);
  1341.     close_s(Curproc->input);
  1342.     /* m->user will be closed automatically when this process exits */
  1343.     Curproc->output = Curproc->input = m->user;
  1344.     /* We'll do our own flushing right before we read input */
  1345.     setflush(m->user,-1);
  1346.  
  1347.     if(fwdinit(m) == -1) {
  1348.         /* it is probably not the right time to forward anymore */
  1349.         fwdcleanup (a, m, NULLCHAR);
  1350.         return;
  1351.     }
  1352.     /* read the connect script. Lines starting with a dot will be sent
  1353.      * to the remote BBS.
  1354.      */
  1355.     Continue[0] = '\0';
  1356.     while((cp=fgets(m->line,MBXLINE,m->tfile)) != NULLCHAR) {
  1357.         if (*m->line == '#' || *m->line == '=' || *m->line == '\n')
  1358.             continue;
  1359.         /* Expanded to do timeouts, and return string recognition - WG7J */
  1360.         if(*m->line == '.') {           /* send this line */
  1361.             tputs(m->line + 1);
  1362.             if(Mtrace)
  1363.                 printf("fwd: %s > %s\n",m->name,m->line+1);
  1364.             Continue[0] = '\0';         /* reset reply string */
  1365.         } else if(*m->line == '+') {    /* string upon wich we continue ! */
  1366.             strcpy(Continue,m->line+1);
  1367.             rip(Continue);              /* get rid of \n */
  1368.         } else if(*m->line == '@') {    /* string that sets timeout */
  1369.             timeout = atoi(m->line+1);
  1370.             if(timeout)                 /* if a valid conversion */
  1371.                 timeout *= 1000;        /* in ms ! */
  1372.             else
  1373.                 timeout = 90*1000L;     /* default to 1.5 minutes */
  1374.             if(Mtrace)
  1375.                 printf("fwd: %s, wait %ld < %s\n",m->name,timeout/1000,Continue);
  1376.             /* Now do the actual response interpretations */
  1377.             alarm(timeout);
  1378.             rval = recvline(m->user,m->line,MBXLINE);
  1379.             alarm(0L);
  1380.             /* Did we timeout, or connection disappear ? */
  1381.             if(Mtrace) {
  1382.                 printf("fwd: %s, rx %d",m->name,rval);
  1383.                 if(rval >= 0)
  1384.                     printf(", %s",m->line);
  1385.                 else
  1386.                     putchar('\n');
  1387.             }
  1388.             if((rval < 0) || (strstr(m->line,Continue) == NULLCHAR)) {
  1389.                 fwdcleanup (a, m, "fwd: %s, aborted!\n");
  1390.                 return;
  1391.             }
  1392.             Continue[0] = '\0';         /* reset reply string */
  1393.         } else      /* must be the end of the script */
  1394.             goto go_on;
  1395.  
  1396.         usflush(m->user);   /* send it, if any */
  1397.     }
  1398.     /* Now we've past all in-between stuff, go talk to the bbs ! */
  1399. go_on:
  1400.     usflush(m->user);
  1401.     fclose(m->tfile);
  1402.     m->tfile = NULLFILE;
  1403.  
  1404.     /* make sure there is something left ! */
  1405.     if(cp == NULLCHAR) {
  1406.         fwdcleanup (a, m, "fwd: forward.bbs error!\n");
  1407.         return;
  1408.     }
  1409.     if(Mtrace)
  1410.         printf("fwd: %s, script done\n",m->name);
  1411.  
  1412.     /* read the initial output from the bbs, looking for the SID */
  1413.     for(;;) {
  1414.                 timeout = 120*1000L;     /* wait up to 2 minutes for each response line */
  1415.         if(Mtrace)
  1416.                     printf("fwd: %s, wait %ld < %s\n",m->name,timeout/1000,">");
  1417.         alarm(timeout);
  1418.         rval = recvline(m->user,m->line,MBXLINE);
  1419.         alarm(0L);
  1420.         if(rval == -1) {
  1421.             fwdcleanup (a, m, NULLCHAR);
  1422.             return;
  1423.         }
  1424.         if(ISPROMPT(m->line))
  1425.             break;
  1426.         if(*m->line == '[') {        /* parse the SID */
  1427.             rip(m->line);
  1428.             mbx_parse(m);
  1429.             continue;
  1430.         }
  1431.     }
  1432.     /* Now sync the two ends as telnet password messes them up */
  1433.     if(socklen(m->user,0))        /* discard any remaining input */
  1434.         recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  1435.  
  1436.     /* send our SID if the peer announced its SID */
  1437.     if(m->sid & MBX_SID) {
  1438.         tputs(FWDlzw ? MboxIdFwd : MboxId);
  1439.         usflush(m->user);
  1440. #ifdef LZW
  1441.         /* If we both support it, go into compression here */
  1442.             if (FWDlzw && m->sid & MBX_TNOS)
  1443.                 togglelzw (m->user, 1);        
  1444. #endif
  1445.         for(;;) {
  1446.             if(recvline(m->user,m->line,MBXLINE) == -1) {
  1447.                 exitbbs(m);
  1448.                 return;
  1449.             }
  1450.             if(ISPROMPT(m->line))
  1451.                 break;
  1452.         }
  1453.     }
  1454.     /* start the actual forwarding */
  1455.     dorevfwd(0,NULL,(void *)m);
  1456.     /* ask for reverse forwarding or just disconnect */
  1457.     if(((m->sid & MBX_SID) && tputs("F>\n") == -1) ||
  1458.        (m->sid & MBX_SID) == 0) {
  1459.            fwdcleanup (a, m, NULLCHAR);
  1460.         close_s(Curproc->output);
  1461.         return;
  1462.     }
  1463.     usflush(m->user);
  1464.     /* parse the commands that are are received during reverse
  1465.      * forwarding.
  1466.      */
  1467.     while(recvline(m->user,m->line,MBXLINE) > 0) {
  1468.         if (m->privs & EXCLUDED_CMD)
  1469.             break;
  1470.         rip(m->line);
  1471.         if((rval = mbx_parse(m)) == -2)    /* got the "*** Done" command */
  1472.             break;
  1473.         if (rval && BBSdump)    /* we dump for all unknowns! */
  1474.             break;
  1475.         if (m->privs & EXCLUDED_CMD)
  1476.             break;
  1477.         tputs("F>\n");
  1478.         usflush(m->user);
  1479.     }
  1480. #if 0
  1481. /*    if((m->sid & MBX_RLI_SID) || (m->sid & MBX_FBB))    {    */    /* disconnect if it is a W0RLI or FBB bbs */
  1482.     if(m->sid & MBX_RLI_SID)    {    /* disconnect if it is a W0RLI bbs */
  1483.         domboxbye(0,NULL,m);
  1484.         return;
  1485.     }
  1486. #else
  1487.     domboxbye(0,NULL,m);
  1488. #endif
  1489.     if ((m->sid & MBX_SID) && m->mysize)
  1490.             smtptick(NULL);        /* wake SMTP to send that mail */
  1491.     fwdcleanup (a, m, NULLCHAR);
  1492.         usflush(Curproc->output);
  1493.     mspause(500L);
  1494.     close_s(Curproc->output);
  1495. }
  1496.  
  1497. /* open a network connection based upon information in the cc line.
  1498.  * m->user is set to the socket number.
  1499.  */
  1500. static int
  1501. openconn(argc,argv,p)
  1502. int argc;
  1503. char *argv[];
  1504. void *p;
  1505. {
  1506.     struct mbx *m;
  1507.     char sock[MAXSOCKSIZE], *np, alias[AXBUF];
  1508. #ifdef NETROM
  1509.     struct nrroute_tab *rp;
  1510. #endif
  1511.     union sp sp;
  1512.     int len;
  1513.  
  1514.     m = (struct mbx *)p;
  1515.     sp.p = sock;
  1516.     if(argc < 2)
  1517.         return -1;
  1518.     switch(*argv[0]) {
  1519.     case 't':
  1520.         sp.in->sin_family = AF_INET;
  1521.         if((sp.in->sin_addr.s_addr = resolve(argv[1])) == 0)
  1522.             return -1;
  1523.         /* get the optional port number */
  1524.         if(argc > 2)
  1525.             sp.in->sin_port = atoip(argv[2]);
  1526.         else
  1527.             sp.in->sin_port = IPPORT_TELNET;
  1528.         if((m->user = socket(AF_INET,SOCK_STREAM,0)) == -1)
  1529.             return -1;
  1530.         len = sizeof(*sp.in);
  1531.         m->family = AF_INET; /*So the user list will be correct! - WG7J */
  1532.         break;
  1533. #ifdef AX25
  1534.     case 'a':
  1535.     case 'c':    /* allow 'c' for 'connect' as well */
  1536.         if(argc < 3)
  1537.             return -1;
  1538.         sp.ax->sax_family = AF_AX25;
  1539.         strncpy(sp.ax->iface,argv[1],ILEN); /* the interface name */
  1540.         setcall(sp.ax->ax25_addr,argv[2]); /* the remote callsign */
  1541.         /* no digipeaters for now, use the "ax25 route add" command */
  1542.         if((m->user = socket(AF_AX25,SOCK_STREAM,0)) == -1)
  1543.             return -1;
  1544.         len = sizeof(*sp.ax);
  1545.         m->family = AF_AX25; /*So the user list will be correct! - WG7J */
  1546.         break;
  1547. #endif /* AX25 */
  1548. #ifdef NETROM
  1549.     case 'n':
  1550.         /* See if the requested destination could be an alias, and
  1551.          * use it if it is.  Otherwise assume it is an AX.25
  1552.          * address.
  1553.          */
  1554.         putalias(alias,argv[1],0);
  1555.         strupr(argv[1]);
  1556.         if ((rp = find_nrboth(alias,argv[1])) == NULLNRRTAB)  {
  1557.             if(Mtrace)
  1558.             tprintf("fwd: Netrom route unavailable - %s\n",argv[1]);
  1559.             return -1;
  1560.         }
  1561.         /* Setup the local side of the connection */
  1562.         sp.nr->nr_family = AF_NETROM;
  1563.         len = sizeof(*sp.nr);
  1564.         if((m->user = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1) {
  1565.              if(Mtrace)
  1566.               tprintf("fwd: unable to open netrom socket - %s\n",argv[1]);
  1567.             
  1568.              return -1;
  1569.         }
  1570.         memcpy(sp.nr->nr_addr.user,Nr4user,AXALEN);
  1571.         memcpy(sp.nr->nr_addr.node,Nr_iface->hwaddr,AXALEN);
  1572.         bind(m->user,sp.p,len);
  1573.  
  1574.         /* Now the remote side */
  1575.         memcpy(sp.nr->nr_addr.node,rp->call,AXALEN) ;
  1576.         /* The user callsign of the remote station is never
  1577.          * used by NET/ROM, but it is needed for the psocket() call.
  1578.          */
  1579.         memcpy(sp.nr->nr_addr.user,rp->call,AXALEN) ;
  1580.  
  1581.         m->family = AF_NETROM; /*So the user list will be correct! - WG7J */
  1582.     break;
  1583. #endif /* NETROM */
  1584.     default:
  1585.         return -1;
  1586.     }
  1587.     sockmode(m->user,SOCK_ASCII);
  1588.     if(connect(m->user,sp.p,len) == -1) {
  1589.         log(m->user,"MBOX forward failed: %s errno %d",
  1590.                 sockerr(m->user),errno);
  1591.         close_s(m->user);
  1592.         return -1;
  1593.     }
  1594.     return m->user;
  1595. }
  1596.  
  1597.  
  1598. void
  1599. forwardingSummary()
  1600. {
  1601. int k;
  1602. register FILE *fp;
  1603. char buf[100], *cp;
  1604. int totbul = 0, totper = 0, bul, per;
  1605.  
  1606.     for (k = 0; k < Numfwds; k++)        {
  1607.         sprintf(buf,"%s/%s.fwd",Mailspool,MyFwds[k]);
  1608.         per = bul = 0;
  1609.         if((fp = fopen(buf,READ_TEXT)) != NULLFILE)    {
  1610.             while (fgets(buf,sizeof(buf),fp) != NULLCHAR)
  1611.                 if (*buf == ' ')    {
  1612.                     cp = strchr (&buf[1], ' ');
  1613.                     if (cp)        {
  1614.                         *cp++ = 0;
  1615.                         if (isarea (&buf[1]))
  1616.                             bul++;
  1617.                         else
  1618.                             per++;
  1619.                     }
  1620.                 }
  1621.             fclose(fp);
  1622.         }
  1623.         tprintf ("Queued for forwarding to %-10.10s:   Bulletins/Personal (%5d/%-5d)\n", MyFwds[k], bul, per);
  1624.         totbul += bul;
  1625.         totper += per;
  1626.     }
  1627.     if (k)
  1628.         tprintf ("Total messages to forward          :   Bulletins/Personal (%5d/%-5d)\n\n", totbul, totper);
  1629.     else
  1630.         tprintf ("You have no BBS's in your 'forward.bbs' file!\n");
  1631. }
  1632.  
  1633.  
  1634. int
  1635. AREAlookup (area, index)
  1636. char *area;
  1637. int index;
  1638. {
  1639. FILE *fp;
  1640. int start = 1;
  1641. int checking = 0;
  1642. char *cp;
  1643. char line[80];
  1644. int retval = 0;
  1645.  
  1646. /*    if(Checklock)
  1647.           return retval;    */
  1648.     if((fp=fopen(Forwardfile,READ_TEXT)) == NULLFILE)
  1649.         return retval;
  1650.     /*Now scan the forward.bbs file to find bbs's*/
  1651.     while(fgets(line,sizeof(line),fp) != NULLCHAR) {
  1652.         if(*line == '\n')
  1653.             continue;
  1654.         if(*line == '#')
  1655.             continue;
  1656.         if(*line == '.' || *line == '+' || *line == '@' || *line == '=')
  1657.             continue;
  1658.         /* lines starting with '-' separate the forwarding records */
  1659.         if(*line == '-') {
  1660.             start = 1;
  1661.             checking = 0;
  1662.             continue;
  1663.         }
  1664.         if (checking && !strnicmp (area, line, strlen(area)))    {
  1665.         cp = &line[strlen(area)];
  1666.         if (*cp == ' ' || *cp == '\n' || *cp == '\t')    {
  1667.             retval = 1;
  1668.             break;
  1669.         }
  1670.     }
  1671.         if(start) {
  1672.             start = 0;
  1673.             if (checking)
  1674.                 break;
  1675.             /* get the name of this forwarding record */
  1676.             if((cp=strpbrk(line," \n\t")) != NULLCHAR)
  1677.                 *cp = '\0';
  1678.             if(strlen(line) > FWDBBSLEN)
  1679.                 continue;   /*What kind of bbs-call is this ?*/
  1680.             if (!stricmp (MyFwds[index], line))
  1681.                 checking = 1;
  1682.         }
  1683.     }
  1684.     fclose(fp);
  1685.     return retval;
  1686. }
  1687.  
  1688.  
  1689. #endif /*MBFWD*/
  1690.